home *** CD-ROM | disk | FTP | other *** search
- /*
- json2.js
- 2008-02-14
-
- Public Domain
-
- No warranty expressed or implied. Use at your own risk.
-
- See http://www.JSON.org/js.html
-
- This file creates a global JSON object containing two methods:
-
- JSON.stringify(value, whitelist)
- value any JavaScript value, usually an object or array.
-
- whitelist an optional array parameter that determines how object
- values are stringified.
-
- This method produces a JSON text from a JavaScript value.
- There are three possible ways to stringify an object, depending
- on the optional whitelist parameter.
-
- If an object has a toJSON method, then the toJSON() method will be
- called. The value returned from the toJSON method will be
- stringified.
-
- Otherwise, if the optional whitelist parameter is an array, then
- the elements of the array will be used to select members of the
- object for stringification.
-
- Otherwise, if there is no whitelist parameter, then all of the
- members of the object will be stringified.
-
- Values that do not have JSON representaions, such as undefined or
- functions, will not be serialized. Such values in objects will be
- dropped; in arrays will be replaced with null.
- JSON.stringify(undefined) returns undefined. Dates will be
- stringified as quoted ISO dates.
-
- Example:
-
- var text = JSON.stringify(['e', {pluribus: 'unum'}]);
- // text is '["e",{"pluribus":"unum"}]'
-
- JSON.parse(text, filter)
- This method parses a JSON text to produce an object or
- array. It can throw a SyntaxError exception.
-
- The optional filter parameter is a function that can filter and
- transform the results. It receives each of the keys and values, and
- its return value is used instead of the original value. If it
- returns what it received, then structure is not modified. If it
- returns undefined then the member is deleted.
-
- Example:
-
- // Parse the text. If a key contains the string 'date' then
- // convert the value to a date.
-
- myData = JSON.parse(text, function (key, value) {
- return key.indexOf('date') >= 0 ? new Date(value) : value;
- });
-
- This is a reference implementation. You are free to copy, modify, or
- redistribute.
-
- Use your own copy. It is extremely unwise to load third party
- code into your pages.
- */
-
- /*jslint evil: true */
-
- /*global JSON */
-
- /*members "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
- charCodeAt, floor, getUTCDate, getUTCFullYear, getUTCHours,
- getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, length,
- parse, propertyIsEnumerable, prototype, push, replace, stringify, test,
- toJSON, toString
- */
-
- if (!this.JSON) {
-
- JSON = function () {
-
- function f(n) { // Format integers to have at least two digits.
- return n < 10 ? '0' + n : n;
- }
-
- Date.prototype.toJSON = function () {
-
- // Eventually, this method will be based on the date.toISOString method.
-
- return this.getUTCFullYear() + '-' +
- f(this.getUTCMonth() + 1) + '-' +
- f(this.getUTCDate()) + 'T' +
- f(this.getUTCHours()) + ':' +
- f(this.getUTCMinutes()) + ':' +
- f(this.getUTCSeconds()) + 'Z';
- };
-
-
- var m = { // table of character substitutions
- '\b': '\\b',
- '\t': '\\t',
- '\n': '\\n',
- '\f': '\\f',
- '\r': '\\r',
- '"' : '\\"',
- '\\': '\\\\'
- };
-
- function stringify(value, whitelist) {
- var a, // The array holding the partial texts.
- i, // The loop counter.
- k, // The member key.
- l, // Length.
- r = /["\\\x00-\x1f\x7f-\x9f]/g,
- v; // The member value.
-
- switch (typeof value) {
- case 'string':
-
- // If the string contains no control characters, no quote characters, and no
- // backslash characters, then we can safely slap some quotes around it.
- // Otherwise we must also replace the offending characters with safe sequences.
-
- return r.test(value) ?
- '"' + value.replace(r, function (a) {
- var c = m[a];
- if (c) {
- return c;
- }
- c = a.charCodeAt();
- return '\\u00' + Math.floor(c / 16).toString(16) +
- (c % 16).toString(16);
- }) + '"' :
- '"' + value + '"';
-
- case 'number':
-
- // JSON numbers must be finite. Encode non-finite numbers as null.
-
- return isFinite(value) ? String(value) : 'null';
-
- case 'boolean':
- case 'null':
- return String(value);
-
- case 'object':
-
- // Due to a specification blunder in ECMAScript,
- // typeof null is 'object', so watch out for that case.
-
- if (!value) {
- return 'null';
- }
-
- // If the object has a toJSON method, call it, and stringify the result.
-
- if (typeof value.toJSON === 'function') {
- return stringify(value.toJSON());
- }
- a = [];
- if (typeof value.length === 'number' &&
- !(value.propertyIsEnumerable('length'))) {
-
- // The object is an array. Stringify every element. Use null as a placeholder
- // for non-JSON values.
-
- l = value.length;
- for (i = 0; i < l; i += 1) {
- a.push(stringify(value[i], whitelist) || 'null');
- }
-
- // Join all of the elements together and wrap them in brackets.
-
- return '[' + a.join(',') + ']';
- }
- if (whitelist) {
-
- // If a whitelist (array of keys) is provided, use it to select the components
- // of the object.
-
- l = whitelist.length;
- for (i = 0; i < l; i += 1) {
- k = whitelist[i];
- if (typeof k === 'string') {
- v = stringify(value[k], whitelist);
- if (v) {
- a.push(stringify(k) + ':' + v);
- }
- }
- }
- } else {
-
- // Otherwise, iterate through all of the keys in the object.
-
- for (k in value) {
- if (typeof k === 'string') {
- v = stringify(value[k], whitelist);
- if (v) {
- a.push(stringify(k) + ':' + v);
- }
- }
- }
- }
-
- // Join all of the member texts together and wrap them in braces.
-
- return '{' + a.join(',') + '}';
- }
- }
-
- return {
- stringify: stringify,
- parse: function (text, filter) {
- var j;
-
- function walk(k, v) {
- var i, n;
- if (v && typeof v === 'object') {
- for (i in v) {
- if (Object.prototype.hasOwnProperty.apply(v, [i])) {
- n = walk(i, v[i]);
- if (n !== undefined) {
- v[i] = n;
- } else {
- delete v[i];
- }
- }
- }
- }
- return filter(k, v);
- }
-
-
- // Parsing happens in three stages. In the first stage, we run the text against
- // regular expressions that look for non-JSON patterns. We are especially
- // concerned with '()' and 'new' because they can cause invocation, and '='
- // because it can cause mutation. But just to be safe, we want to reject all
- // unexpected forms.
-
- // We split the first stage into 4 regexp operations in order to work around
- // crippling inefficiencies in IE's and Safari's regexp engines. First we
- // replace all backslash pairs with '@' (a non-JSON character). Second, we
- // replace all simple value tokens with ']' characters. Third, we delete all
- // open brackets that follow a colon or comma or that begin the text. Finally,
- // we look to see that the remaining characters are only whitespace or ']' or
- // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
-
- if (/^[\],:{}\s]*$/.test(text.replace(/\\./g, '@').
- replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
- replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
-
- // In the second stage we use the eval function to compile the text into a
- // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
- // in JavaScript: it can begin a block or an object literal. We wrap the text
- // in parens to eliminate the ambiguity.
-
- j = eval('(' + text + ')');
-
- // In the optional third stage, we recursively walk the new structure, passing
- // each name/value pair to a filter function for possible transformation.
-
- return typeof filter === 'function' ? walk('', j) : j;
- }
-
- // If the text is not JSON parseable, then a SyntaxError is thrown.
-
- throw new SyntaxError('parseJSON');
- }
- };
- }();
- }
-